
#include <GL/gl.h>
#include "CameraMode.h"
#include "../MathUtil.h"

CameraMode::CameraMode() {

    _matrix = new aiMatrix4x4();
    setIdentity(_matrix);

    _rotate_speed = 10.0;
    _zoom_speed = 1.0;
    _translate_speed = 100.0;

    _rotate = new aiVector3D();
    _zoom = new aiVector3D();
    _translate = new aiVector3D();

    _rotate_vec = new aiVector3D();
    _translate_vec = new aiVector3D();
    _zoom_vec = new aiVector3D();

    _rotate_min = new aiVector3D(-1.5, -9999, -9999);
    _rotate_max = new aiVector3D(1.5, 9999, 9999);

    _translate_min = new aiVector3D();
    _translate_max = new aiVector3D();

    _zoom_min = new aiVector3D();
    _zoom_max = new aiVector3D();

    _mouse_sensitivity = 500.0;
    //    _key_handlers[SDLK_LEFT] = tuple<aiVector3D*, aiVector3D > (_rotate_vec, aiVector3D(0.0, 1.0, 0.0));
    //    _key_handlers[SDLK_RIGHT] = tuple<aiVector3D*, aiVector3D > (_rotate_vec, aiVector3D(0.0, -1.0, 0.0));
    //    _key_handlers[SDLK_UP] = tuple<aiVector3D*, aiVector3D > (_rotate_vec, aiVector3D(1.0, 0.0, 0.0));
    //    _key_handlers[SDLK_DOWN] = tuple<aiVector3D*, aiVector3D > (_rotate_vec, aiVector3D(-1.0, 0.0, 0.0));
    //    _key_handlers[SDLK_w] = tuple<aiVector3D*, aiVector3D > (_translate_vec, aiVector3D(0.0, 0.0, -1.0));
    //    _key_handlers[SDLK_s] = tuple<aiVector3D*, aiVector3D > (_translate_vec, aiVector3D(0.0, 0.0, 1.0));
    //    _key_handlers[SDLK_a] = tuple<aiVector3D*, aiVector3D > (_translate_vec, aiVector3D(-1.0, 0.0, 0.0));
    //    _key_handlers[SDLK_d] = tuple<aiVector3D*, aiVector3D > (_translate_vec, aiVector3D(1.0, 0.0, 0.0));
    //    _key_handlers[SDLK_SPACE] = tuple<aiVector3D*, aiVector3D > (_translate_vec, aiVector3D(0.0, 1.0, 0.0));
    //    _key_handlers[SDLK_z] = tuple<aiVector3D*, aiVector3D > (_translate_vec, aiVector3D(0.0, -1.0, 0.0));

    _translate->Set(0, 10.0f, 10.0f);

}

CameraMode::~CameraMode() {
    delete _matrix;

    delete _rotate;
    delete _zoom;
    delete _translate;

    delete _rotate_vec;
    delete _translate_vec;
    delete _zoom_vec;

    delete _rotate_min;
    delete _rotate_max;

    delete _translate_min;
    delete _translate_max;

    delete _zoom_min;
    delete _zoom_max;
}

void CameraMode::rotate_camera(aiVector3D* vec) {
    *_rotate_vec += *vec;
}

void CameraMode::translate_camera(aiVector3D* vec) {
    *_translate_vec += *vec;
}

void CameraMode::zoom_camera(aiVector3D* vec) {
    *_zoom_vec += *vec;
}

void CameraMode::resume() {

}

void CameraMode::pause() {

}

void CameraMode::apply() {
    //double v[16];
    //getInverseV(_matrix, v);
    aiMatrix4x4 m = *_matrix;
    m.Transpose();
    m.Inverse();
    glLoadMatrixf((GLfloat*) & m);
}

void CameraMode::input(SDL_Event* evt, unsigned int ms) {

    if (evt->type == SDL_MOUSEMOTION) {

        if (!(evt->motion.x == 50 && evt->motion.y == 50)) {
            int x = evt->motion.x - 50;
            int y = evt->motion.y - 50;


            _rotate->y = clampf(_rotate->y - ((float) x / _mouse_sensitivity), _rotate_min->y, _rotate_max->y);
            _rotate->x = clampf(_rotate->x - ((float) y / _mouse_sensitivity), _rotate_min->x, _rotate_max->x);
            SDL_WarpMouse(50, 50);
        }
    } else if (evt->type == SDL_KEYDOWN) {

        aiVector3D* s = 0;
        aiVector3D* o = 0;
        switch (evt->key.keysym.sym) {
            case SDLK_w:
                s = _translate_vec;
                o = new aiVector3D(0.0, 0.0, -1.0);
                break;
            case SDLK_s:
                s = _translate_vec;
                o = new aiVector3D(0.0, 0.0, 1.0);
                break;
            case SDLK_a:
                s = _translate_vec;
                o = new aiVector3D(-1.0, 0.0, 0.0);
                break;
            case SDLK_d:
                s = _translate_vec;
                o = new aiVector3D(1.0, 0.0, 0.0);
                break;
            case SDLK_z:
                s = _translate_vec;
                o = new aiVector3D(0.0, -1.0, 0.0);
                break;
            case SDLK_SPACE:
                s = _translate_vec;
                o = new aiVector3D(0.0, 1.0, 0.0);
                break;
            case SDLK_LEFT:
                s = _rotate_vec;
                o = new aiVector3D(0.0, 1.0, 0.0);
                break;
            case SDLK_RIGHT:
                s = _rotate_vec;
                o = new aiVector3D(0.0, -1.0, 0.0);
                break;
            case SDLK_UP:
                s = _rotate_vec;
                o = new aiVector3D(1.0, 0.0, 0.0);
                break;
            case SDLK_DOWN:
                s = _rotate_vec;
                o = new aiVector3D(-1.0, 0.0, 0.0);
                break;
            default: break;
        }
        if (s && o) {
            *s += *o;
        }
        delete o;
    } else if (evt->type == SDL_KEYUP) {
        aiVector3D* s = 0;
        aiVector3D* o = 0;
        switch (evt->key.keysym.sym) {
            case SDLK_w:
                s = _translate_vec;
                o = new aiVector3D(0.0, 0.0, -1.0);
                break;
            case SDLK_s:
                s = _translate_vec;
                o = new aiVector3D(0.0, 0.0, 1.0);
                break;
            case SDLK_a:
                s = _translate_vec;
                o = new aiVector3D(-1.0, 0.0, 0.0);
                break;
            case SDLK_d:
                s = _translate_vec;
                o = new aiVector3D(1.0, 0.0, 0.0);
                break;
            case SDLK_z:
                s = _translate_vec;
                o = new aiVector3D(0.0, -1.0, 0.0);
                break;
            case SDLK_SPACE:
                s = _translate_vec;
                o = new aiVector3D(0.0, 1.0, 0.0);
                break;
            case SDLK_LEFT:
                s = _rotate_vec;
                o = new aiVector3D(0.0, 1.0, 0.0);
                break;
            case SDLK_RIGHT:
                s = _rotate_vec;
                o = new aiVector3D(0.0, -1.0, 0.0);
                break;
            case SDLK_UP:
                s = _rotate_vec;
                o = new aiVector3D(1.0, 0.0, 0.0);
                break;
            case SDLK_DOWN:
                s = _rotate_vec;
                o = new aiVector3D(-1.0, 0.0, 0.0);
                break;
            default: break;
        }
        if (s && o) {
            *s -= *o;
        }
        delete o;
    }
}

void CameraMode::_update_rotate(unsigned int ms) {
    *_rotate += (*_rotate_vec) * _rotate_speed * ms / 1000.0f;
}

void CameraMode::_update_translate(unsigned int ms) {
    aiVector3D heading;
    aiVector3D strafe;
    aiVector3D up;

    getAxes(_matrix, &strafe, &up, &heading);
    aiVector3D _tc = strafe * _translate_vec->x + up * _translate_vec->y + heading * _translate_vec->z;

    *_translate += (_tc) * _translate_speed * ms / 1000.f;
}

void CameraMode::_update_zoom(unsigned int ms) {

}

void CameraMode::update(unsigned int ms) {
    if (_rotate_vec->SquareLength() > 0) {
        _update_rotate(ms);
    }
    if (_translate_vec->SquareLength() > 0) {
        _update_translate(ms);
    }

    //aiIdentityMatrix4(_matrix);
    setIdentity(_matrix);
    applyTranslation(_matrix, _translate);
    applyRotationY(_matrix, _rotate->y);
    applyRotationX(_matrix, _rotate->x);
}